﻿#ifndef __INC_KH_CODE_H__
#define __INC_KH_CODE_H__

#ifdef _MSC_VER
#pragma once
#endif

//////////////////////////////////////////////////////////////////////////
// data code declare

// scope
enum khScope
{
	KHSCP_UNKNOWN = -1,
	KHSCP_PUBLIC = -2,
	KHSCP_SELF = -3,
	KHSCP_LOCAL = 0
};

// loop
enum khLoop
{
	KHLP_UNKNOWN,
	KHLP_BINARY,
	KHLP_WHILE,
	KHLP_DOWHILE,
	KHLP_FOR,
	KHLP_FOREACH,
	KHLP_SWITCH
};

// instruction address
union khInstAddr
{
	kbyte*				p8;
	kushort*			p16;
	kuint*				p32;
	kulong*				p64;
};

// variable
struct khVarData
{
	kuint				sym;
	kint				off;
	kcham				asgn : 16;
	kcham				impl : 16;
	khToken*			token;
};

// loop
struct khLoopData
{
	enum khLoop			stmt;
	kint				brk;
	kint				ctn;
};

// patch
struct khPatchData
{
	kint				addr;
	kint				next;
};

// branch
struct khBranchData
{
	kint				addr;
	kcham				isif;
};

// switch
struct khSwitchData
{
	kint				tbl;
	kint				addr;
	kbool				onlydef;
};

// label
struct khLabelData
{
	kint				ref;
	kint				addr;
	struct khToken*		token;
};

//
K_ARR_DECL(khConstArr, kVar);
K_ARR_DECL(khVarArr, struct khVarData);
K_ARR_DECL(khBranchArr, struct khBranchData);
K_ARR_DECL(khLabelArr, struct khLabelData);
K_ARR_DECL(khLoopArr, struct khLoopData);
K_ARR_DECL(khSwitchArr, struct khSwitchData);
K_ARR_DECL(khPatchArr, struct khPatchData);


//////////////////////////////////////////////////////////////////////////
// code data
typedef struct khCodeData
{
	kuint				cs : 16;	// cur size
	kuint				ms : 16;	// max size

	kint				loc;
	kint				capa;

	kuint*				code;
	kushort*			line;
} khCodeData;

extern void kh_cd_init(khCodeData* cd);
extern void kh_cd_disp(khCodeData* cd);
extern void kh_cd_reset(khCodeData* cd);
extern void kh_cd_expand(khCodeData* cd, kint cnt);
extern kint kh_cd_skip(khCodeData* cd, kuint line);
extern kint kh_cd_skip_2(khCodeData* cd, kuint line);
extern kint kh_cd_skip_nth(khCodeData* cd, kuint line, kint cnt);
extern void kh_cd_emit(khCodeData* cd, kuint line, kuint inst);
extern void kh_cd_emit_op(khCodeData* cd, kuint line, kuint inst, kint op);
extern void kh_cd_emit_addr(khCodeData* cd, kuint line, kuint inst, kint addr);
extern void kh_cd_emit_sym(khCodeData* cd, kuint line, kuint inst, kuint sym);
extern void kh_cd_emit_each(khCodeData* cd, kuint line, kuint inst, kint ko, kint vo);
extern void kh_cd_emit_32(khCodeData* cd, kuint line, kuint inst, kint value);
extern void kh_cd_emit_64(khCodeData* cd, kuint line, kuint inst, klong value);
extern void kh_cd_set_line(khCodeData* cd, kint n, kuint line);
extern kint kh_cd_get_loc(khCodeData* cd);
extern kint kh_cd_swap_loc(khCodeData* cd, kint v);
extern void kh_cd_set_loc(khCodeData* cd, kint v);
extern kuint* kh_cd_get_code(khCodeData* cd);
extern kushort* kh_cd_get_line(khCodeData* cd);
extern kuint kh_cd_get_code_nth(khCodeData* cd, kint n);
extern kuint kh_cd_get_code_inv(khCodeData* cd, kint n);
extern kushort kh_cd_get_line_nth(khCodeData* cd, kint n);
extern kushort kh_cd_get_line_inv(khCodeData* cd, kint n);


//////////////////////////////////////////////////////////////////////////
// function data
typedef struct khFuncData
{
	struct khFuncData*	prev;
	struct khFuncData*	next;

	khCodeData			code;			// code

	kUintArr			syms;			// symbols
	kPtrArr				reds;			// red data (fn+str+wcs)

	khBranchArr			brcs;
	khVarArr			vars;
	khLabelArr			lbls;
	khLabelArr			rsvs;

	kint				args;
	kint				lcls;
	kint				tmps;

	kint				index;
	kint				line;
	
	const kchar*		filename;
	const kchar*		name;

	kDateTime			bdt;
	kint				memcap;
} khFuncData;

extern khFuncData* kh_fd_new(void);
extern void kh_fd_delete(khFuncData* fd);
extern void kh_fd_reset(khFuncData* fd, kcham isfailed);
extern void kh_fd_reset_consts(khFuncData* fd);
extern kuint kh_fd_const_sym(khFuncData* fd, const char* str);
extern kint kh_fd_const_str(khFuncData* fd, const char* str);
extern kint kh_fd_const_wcs(khFuncData* fd, const kwchar* str);
extern kint kh_fd_const_fn(khFuncData* fd, kRedFn* fn);
extern kcham kh_fd_var_mark(khFuncData* fd, kint offset);
extern kint kh_fd_var_set(khFuncData* fd, enum khScope scope, khToken* token, kcham append, kcham impl);
extern kint kh_fd_var_get(khFuncData* fd, enum khScope scope, khToken* token, struct khVarData** vd);
extern void kh_fd_branch_add(khFuncData* fd, kuint at, kcham isif);
extern kint kh_fd_label_set(khFuncData* fd, kuint addr, khToken* token, khToken** rettoken);
extern kint kh_fd_label_get(khFuncData* fd, khToken* token, khToken** rettoken);
extern void kh_fd_label_reserve(khFuncData* fd, kuint addr, khToken* token);


//////////////////////////////////////////////////////////////////////////
// 함수 내 코드
typedef struct khFnCode
{
	const kuint*		inst;
	const kuint*		susp;

	struct
	{
		kint			size;
		kuint*			code;
		kushort*		line;
	}					data;

	struct
	{
		kint			stks;
		kint			args;
		kint			lcls;
		kint			vars;
	}					si;

	//
	kDateTime			bdt;
	kchar*				filename;

	//
	kUintCtn*			syms;
} khFnCode;


//////////////////////////////////////////////////////////////////////////
// 실행 정보

// run info
typedef struct khRunInfo
{
	struct khRunInfo*	next;	// for list
	kScv				data;
} khRunInfo;

// call info
typedef struct khCallInfo
{
	struct khCallInfo*	next;	// for list
	struct khCallInfo*	prev;	// for inter-ref

	khRunInfo*			rri;
	kRedFn*				rfn;

	kint				addr;
	ksize_t				base;
} khCallInfo;

// 진짜 HSM
typedef struct khRealHsm
{
	kBase				base;

	kint				flags;

	kint				parses;
	kint				compiles;

	kint				cstk;
	kanycb				dbgcb;

	kRedTbl*			super;

	kMutex*				lock;

	khRunInfo*			rri;
	khCallInfo*			rci;

	kUintArr			libs;
} khRealHsm;

// 진짜 HSP
typedef struct khRealRnh
{
	kBase				base;

	kint				lerr;

	kHsm*				hsm;
	kRedFn*				cfn;
	kRedTbl*			pub;

	khRunInfo*			rri;
	khCallInfo*			rci;
} khRealRnh;

//
KAPI khRunInfo* k_hsm_alloc_run_info(kHsm* ptr, kRnh* run, kRedTbl* pub);
KAPI khCallInfo* k_hsm_alloc_call_info(kHsm* ptr, khRunInfo* ri, kRedFn* rfn, kint addr, kint base);
KAPI void k_hsm_free_run_info(kHsm* ptr, khRunInfo* ri);
KAPI void k_hsm_free_call_info(kHsm* ptr, khCallInfo* ci);


//////////////////////////////////////////////////////////////////////////
// 그밖에

// 문자열로
KAPI const kchar* kh_tos_token_type(kint v);
KAPI const kchar* kh_tos_token_role(kint v);
KAPI const kchar* kh_tos_scope(kint v);
KAPI const kchar* kh_tos_mnemonic(kint v);

// 디셈블
KAPI kcham kh_dasm_write_file(kFile* file, kRedFn* rfn);
KAPI kcham kh_dasm_write_output(const char* file, kRedFn* rfn);

// RFN
KAPI kcham k_redfn_set_code(kRedFn* self, const khFuncData* fd);
KAPI khFnCode* k_redfn_get_code(kRedFn* self);

#endif	// __INC_KH_CODE_H__
